package com.changge.generator.util;

import com.changge.common.core.enums.CommonErrorCode;
import com.changge.common.core.utils.StringUtil;
import com.changge.common.core.utils.TimeUtil;
import com.changge.generator.config.properties.GeneratorProperties;
import com.changge.generator.dto.GenerateOptionDTO;
import com.changge.generator.domain.Field;
import com.changge.generator.domain.TableColumnInfo;
import com.changge.generator.mapper.GenerateMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.changge.generator.constant.DataBaseConst.*;
import static com.changge.generator.constant.GenerateConst.*;

/**
 * 代码生成工具类
 *
 * @author zhangrongkang
 * @since 2024/1/11
 */
@Component
public class GenerateUtil {

    @Autowired
    private GenerateMapper generateMapper;

    @Autowired
    private GeneratorProperties generatorProperties;

    /**
     * 将表格字段转为可以对应Java数据
     *
     * @param tableColumnList 表格字段集合
     * @return Java数据集合
     */
    public List<Field> castTableColumnToField(List<TableColumnInfo> tableColumnList) {
        List<Field> result = new ArrayList<>();
        for (TableColumnInfo tableColumnInfo : tableColumnList) {
            Field field = new Field();
            // 列名
            field.setColumnName(tableColumnInfo.getColumnName());
            // 列注释
            field.setComment(tableColumnInfo.getColumnComment());
            // 是否可以为空
            field.setIsNull(tableColumnInfo.getIsNullable().equals(YES) ? Boolean.TRUE : Boolean.FALSE);
            // Java名称
            field.setJavaName(StringUtil.lineToHump(tableColumnInfo.getColumnName(), "_"));
            // Java驼峰名称
            field.setJavaUpName(StringUtil.lineToUpHump(tableColumnInfo.getColumnName()));
            // Java类型
            field.setJavaType(castSqlTypeToJavaType(tableColumnInfo.getColumnType()));
            result.add(field);
        }
        return result;
    }

    /**
     * 将表名转为Java类名
     *
     * @param tableName 表名
     * @return 类名
     */
    public String getEntityName(String tableName) {
        // 去除表格前缀
        tableName = tableName.substring(generatorProperties.getTablePrefix().length());
        // 返回Java类名称
        return StringUtil.lineToUpHump(tableName);
    }

    /**
     * 获取首字母小写后的Java类名
     *
     * @param entityName Java类名
     * @return 首字母小写后的Java类名
     */
    public String getEntityLowerName(String entityName) {
        return entityName.substring(0, 1).toLowerCase() + entityName.substring(1);
    }

    /**
     * 根据表名获取请求路由
     *
     * @param tableName 表名
     * @return 请求路由
     */
    public String getMapping(String tableName) {
        // 去掉表格前缀
        tableName = tableName.substring(generatorProperties.getTablePrefix().length());
        // 返回路径名称
        return tableName.toLowerCase().replace("_", "-");
    }

    /**
     * 将表格字段类型转为Java类型
     *
     * @param columnType 字段类型
     * @return Java类型
     */
    private static String castSqlTypeToJavaType(String columnType) {
        // 将所有字符都转为小写
        String typeCast = columnType.toLowerCase();
        // 判断并返回字符类型
        return switch (typeCast) {
            // 字符类型
            case VARCHAR, TEXT, CHAR, LONG_TEXT -> "String";
            // 整数类型
            case INT -> "Integer";
            case BIG_INT -> "Long";
            case TINY_INT -> "Boolean";
            // 浮点类型
            case DOUBLE -> "Double";
            // 时间类型
            case DATE_TIME -> "LocalDateTime";
            // 默认抛出异常
            default -> throw CommonErrorCode.INTERNAL_SERVER_ERROR.exception();
        };
    }

    /**
     * 设置包路径参数
     *
     * @param generateOptionDTO 代码生成选项数据传输对象
     * @param map 代码生成参数
     */
    public void setPackageAttribute(GenerateOptionDTO generateOptionDTO, Map<String, Object> map) {
        // 包名称
        String packageName = generateOptionDTO.getPackageName();
        // 模块名称
        String moduleName = generateOptionDTO.getModuleName();
        // Controller路径
        map.put(CONTROLLER_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseControllerPackage(), moduleName, packageName));
        // Service路径
        map.put(SERVICE_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseServicePackage(), moduleName, packageName));
        // ServiceImpl路径
        map.put(SERVICE_IMPL_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseServiceImplPackage(), moduleName, packageName));
        // Mapper路径
        map.put(MAPPER_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseMapperPackage(), moduleName, packageName));
        // Domain路径
        map.put(DOMAIN_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseDomainPackage(), moduleName, packageName));
        // DTO路径
        map.put(DTO_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseDtoPackage(), moduleName, packageName));
        // VO路径
        map.put(VO_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseVoPackage(), moduleName, packageName));
        // Query路径
        map.put(QUERY_PACKAGE, StringUtil.messageFormat(generatorProperties.getBaseQueryPackage(), moduleName, packageName));
    }

    /**
     * 设置请求类参数
     *
     * @param generateOptionDTO 代码生成选项数据传输对象
     * @param map 代码生成参数
     */
    public void setClassAttribute(GenerateOptionDTO generateOptionDTO, Map<String, Object> map) {
        String tableName = generateOptionDTO.getTableName();
        // 将表名转为Java类名和Java小写类名
        String entityName = getEntityName(tableName);
        String entityLowerName = getEntityLowerName(entityName);
        // 根据表名获取请求路径名称
        String mapping = getMapping(tableName);

        // 作者名称
        map.put(AUTHOR, generatorProperties.getAuthor());
        // 生成时间
        map.put(DATE, TimeUtil.getNowDate());
        // Java实体类名称
        map.put(ENTITY_NAME, entityName);
        // Java实体类首字母小写
        map.put(ENTITY_LOWER_NAME, entityLowerName);
        // 请求映射路径
        map.put(MAPPING, mapping);
        // 实体类名称（中文）
        map.put(OBJECT_NAME, getObjectName(tableName));
        // 表名
        map.put(TABLE_NAME, tableName);
    }

    /**
     * 设置字段信息参数
     *
     * @param generateOptionDTO 代码生成选项数据传输对象
     * @param map 代码生成参数
     */
    public void setFieldAttribute(GenerateOptionDTO generateOptionDTO, Map<String, Object> map) {
        String tableName = generateOptionDTO.getTableName();
        // 根据表名获取字段数据
        List<TableColumnInfo> tableColumnList = generateMapper.getTableColumnByTableName(tableName);
        List<Field> fieldList = castTableColumnToField(tableColumnList);
        // 字段信息
        map.put(FIELD_LIST, fieldList);
        // 是否开启链式编程
        map.put(ENABLE_CHAIN, generateOptionDTO.getEnableChain());
        // 是否开启二级缓存
        map.put(ENABLE_CACHE, generateOptionDTO.getEnableCache());
    }

    /**
     * 获取实体类名称（中文）
     *
     * @param tableName 表名
     * @return 实体类名称
     */
    public String getObjectName(String tableName) {
        String tableComment = generateMapper.getTableCommentByTableName(tableName);
        if (StringUtil.isEmpty(tableComment)) {
            return getEntityName(tableName);
        }
        return tableComment.substring(0, tableComment.length() - 1);
    }
}
